package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.nacos.common.utils.StringUtils;
import com.heima.common.exception.CustomException;
import com.heima.common.redis.CacheService;
import com.heima.feign.article.IApArticleClient;
import com.heima.file.service.impl.MinIOFileTemplate;
import com.heima.model.common.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.common.pojos.wemedia.WmChannel;
import com.heima.model.common.pojos.wemedia.WmNews;
import com.heima.model.common.pojos.wemedia.WmSensitive;
import com.heima.model.common.pojos.wemedia.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.config.Tess4jClient;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.BaiduScanService;
import com.heima.wemedia.service.WmAutoScanService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author Lijx
 * @Date 2024-07-23 11:47
 */
@Service
public class WmAutoScanServiceImpl implements WmAutoScanService {

    @Autowired
    private WmNewsMapper newsMapper;
    @Autowired
    private BaiduScanService baiduScanService;
    @Autowired
    private IApArticleClient articleClient;
    @Autowired
    private WmUserMapper userMapper;
    @Autowired
    private WmChannelMapper channelMapper;
    @Autowired
    private WmSensitiveMapper sensitiveMapper;
    @Autowired
    private CacheService cacheService;
    @Autowired
    private Tess4jClient tess4jClient;
    @Autowired
    private MinIOFileTemplate minIOTemplate;

    /**
     * 自动审核发布文章
     * @param id
     */
    @Override
    public void autoScan(Integer id) {
        //校验参数
        if (id == null) {
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
        }
        //查询文章信息
        WmNews news = newsMapper.selectById(id);
        if (news.getStatus() == null || news.getStatus() != 1) { //1表示待审核
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
        }

        //获取文章中文本内容和图片
        Map<String, Object> textAndImg = getTextAndImagesInContent(news);

        //先审核文本内容
        boolean textPass = scanText(textAndImg.get("text").toString(),news);
        if (!textPass) {
            return;
        }

        //在审核图片
        boolean imgPass = scanImg((Set<String>)textAndImg.get("image"),news);
        if (!imgPass) {
            return;
        }

        //发起远程feign调用，调用article微服务，将文章信息同步到app端
        saveOrUpdateArticle(news);
    }

    /**
     * 将文章信息同步到app端
     * @param news
     */
    private void saveOrUpdateArticle(WmNews news) {
        ArticleDto articleDto = new ArticleDto();
        //准备数据
        articleDto.setContent(news.getContent());
        BeanUtils.copyProperties(news,articleDto);
        //处理id,authorId,authorName,channelName,layout数据
        if (news.getArticleId() != null) {
            articleDto.setId(news.getArticleId());
        }

        //查询作者信息
        WmUser wmUser = userMapper.selectById(news.getUserId());
        if (wmUser != null) {
            articleDto.setAuthorId(Long.valueOf(news.getUserId()));
            articleDto.setAuthorName(wmUser.getName());
        }

        //查询频道信息
        WmChannel wmChannel = channelMapper.selectById(news.getChannelId());
        if (wmChannel != null) {
            articleDto.setChannelName(wmChannel.getName());
        }

        articleDto.setLayout(news.getType());

        //发送feign远程调用
        ResponseResult responseResult = articleClient.saveOrUpdate(articleDto);
        if (responseResult.getCode() == 200) { //响应成功
            //获取文章保存成功后返回的id
            String articleId = responseResult.getData().toString();
            news.setArticleId(Long.valueOf(articleId));
            news.setStatus((short)9); //设置文章状态为已发布
            news.setReason("审核成功");
            //更新文章信息
            newsMapper.updateById(news);
        }
    }

    /**
     * 调用第三方接口判断图片是否审核通过
     * @param images
     * @param news
     * @return
     */
    private boolean scanImg(Set<String> images, WmNews news) {
        //1. 先内审：基于tess4j进行文本OCR图文识别
        try {
            for (String imgUrl : images) {
                //将图片url转为BufferedImage
                byte[] bytes = minIOTemplate.downLoadFile(imgUrl);
                InputStream is = new ByteArrayInputStream(bytes);
                BufferedImage image = ImageIO.read(is);
                //提取出图片中的文字
                String textInImg = tess4jClient.doOCR(image);
                //如果图片中包含文字，则开启文本审核
                if (StringUtils.isNotEmpty(textInImg)){
                    boolean flag = scanText(textInImg, news);
                    if (!flag){
                        news.setStatus((short)2); //设置状态为不通过
                        news.setReason("审核失败：图片中包含违规文本内容!");
                        //更新文章信息
                        newsMapper.updateById(news);
                        return false;
                    }
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }

        //在外审
        for (String image : images) {
            Integer type = baiduScanService.scanImg(image);
            if (type == 2) { //审核不通过
                news.setStatus((short)2); //设置状态为不通过
                news.setReason("审核不通过：内容违规");
                //更新文章信息
                newsMapper.updateById(news);
                return false;
            }else if (type ==3 || type == 4){
                news.setStatus((short)3); //设置状态为人工审核
                news.setReason("转人工审核：内容疑似违规");
                //更新文章信息
                newsMapper.updateById(news);
                return false;
            }
        }
        return true;
    }

    /**
     * 调用第三方接口判断文本是否审核通过
     * @param text
     * @param news
     * @return
     */
    private boolean scanText(String text, WmNews news) {
        //先内审 自定义敏感词汇经行过滤
        //缓存优化：先查询缓存，缓存有直接用；缓存没有，先查数据库，再添加缓存
        String sensitivesJSON = cacheService.get("sensitives");
        List<String> sensitiveList = JSONArray.parseArray(sensitivesJSON, String.class);
        //缓存没有：再查数据库
        if (sensitiveList == null) {
            //查询自定义敏感词
            List<WmSensitive> wmSensitives = sensitiveMapper.selectList(null);
            sensitiveList = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
            //添加到缓存
            cacheService.set("sensitives", JSON.toJSONString(sensitiveList));
        }

        //初始化DFA算法字典
        SensitiveWordUtil.initMap(sensitiveList);
        //调用DFA算法进行指定文本的敏感词过滤
        Map<String, Integer> map = SensitiveWordUtil.matchWords(text);

        if (map.size() > 0) {
            news.setStatus((short)2); //设置状态为不通过
            news.setReason("审核不通过：内容违规");
            //更新文章信息
            newsMapper.updateById(news);
            return false;
        }

        //在外审
        Integer type = baiduScanService.scanText(text);
        if (type == 2) { //审核不通过
            news.setStatus((short)2); //设置状态为不通过
            news.setReason("审核不通过：内容违规");
            //更新文章信息
            newsMapper.updateById(news);
            return false;
        }else if (type ==3 || type == 4){
            news.setStatus((short)3); //设置状态为人工审核
            news.setReason("转人工审核：内容疑似违规");
            //更新文章信息
            newsMapper.updateById(news);
            return false;
        }
        return true;
    }


    /**
     * 提取文章内容中的素材图片
     * @param news
     * @return
     */
    private Map<String,Object> getTextAndImagesInContent(WmNews news) {
        //创建map对象
        Map<String,Object> result = new HashMap<>();
        //创建StringBuffer存储文本
        StringBuffer buffer = new StringBuffer(news.getTitle());
        buffer.append(news.getLabels());
        //创建集合存储图片路径
        Set<String> urls = new HashSet<>();

        List<Map> maps = JSONArray.parseArray(news.getContent(), Map.class);
        for (Map map : maps) {
            String type = map.get("type").toString();
            //判断是否是图片
            if ("image".equals(type)) {
                String url = map.get("value").toString();
                urls.add(url);
            }
            //判断是否是文本
            if ("text".equals(type)) {
                String text = map.get("value").toString();
                buffer.append(text);
            }
        }

        //判断封面图片是否为空
        if (StringUtils.isNotEmpty(news.getImages())) {
            String[] imgs = news.getImages().split(",");
            Collections.addAll(urls,imgs);
        }

        //将文本添加到map中
        result.put("text",buffer.toString());
        //将图片添加到map中
        result.put("image",urls);

        return result;
    }
}



























